#include "CompresorDeTerminos.h"
#include "FrontCoding.h"
#include "Parser.h"
#include <stdio.h>

CompresorDeTerminos::CompresorDeTerminos(const std::string &path_salida_lexico, const std::string
		&path_salida_punteros, const std::string &path_tabla) {
	this->path_lexico = path_salida_lexico;
	this->path_punteros = path_salida_punteros;
	this->pos_lexico = 0;
	this->pos_punteros = 0;
	this->buffer_lexico = new char[LEXICO_SIZE];
	memset(this->buffer_lexico, 0, LEXICO_SIZE);
	this->path_tabla = path_tabla;
}

CompresorDeTerminos::~CompresorDeTerminos() {
	delete[] this->buffer_lexico;
}

void CompresorDeTerminos::comprimir(const std::string &path_entrada, const std::string &path_info) {
	int longitud = 0;
	int longitud_anterior = 0;
	unsigned short int cant_doc;
	this->pos_lexico_offset = 0;
	FILE* info =  fopen(path_info.c_str(), "r");
	int cant_terminos = 0;
	fread(&cant_terminos,sizeof(int),1,info);
	this->tabla.set_entradas(cant_terminos);
	fclose(info);

	FILE* input = fopen(path_entrada.c_str(), "r");
	this->lexico= fopen(this->path_lexico.c_str(),"w+");
	this->compresorPunteros.setPath(this->path_punteros);

	fseek(input, 0L, SEEK_END );
	int final = ftell(input);
	fseek(input,0L, SEEK_SET);
	bool salida = false;
	char* buffer = new char[final];
	memset(buffer,0,final);
	int contador = 0;
	char* aux = buffer;
	fread(buffer, final, sizeof(char), input);

	char termino_actual[LONG_TERMINO_MAX];
	char termino_anterior[LONG_TERMINO_MAX];

	int CANTIDAD = 0;
	while (!salida) {
		memset(termino_actual, 0 , LONG_TERMINO_MAX);
		longitud = 0;
		memcpy(termino_actual,aux,LONG_TERMINO_MAX);
		aux = aux + LONG_TERMINO_MAX;
		memcpy(&cant_doc,aux, sizeof(unsigned short int));
		aux = aux +  sizeof(unsigned short int);
		contador = contador + sizeof(unsigned short int) + LONG_TERMINO_MAX;
		Doc_frec* par[cant_doc];

		int i = 0;
		unsigned short int doc_anterior = 0;
		unsigned short int doc = 0;
		unsigned short int frec = 0;

		while (i < cant_doc ) {

			memcpy(&doc, aux, sizeof(unsigned short int));
			aux = aux +  sizeof(unsigned short int);
			memcpy(&frec, aux, sizeof(unsigned short int));
			aux = aux+  sizeof(unsigned short int);
			par[i] = new Doc_frec();
			par[i]->doc = doc - doc_anterior;
			par[i]->frec = frec;
			doc_anterior = doc;
			i++;
		}

		contador = contador + (cant_doc*2* sizeof(unsigned short int));
		if (contador >= final) {
			salida = true;
		}


		bool end  = false;
		while ((!end) && (longitud < LONG_TERMINO_MAX)) {
			if (termino_actual[longitud] == '\0') {
				end = true;
			}
			else {
				longitud++;
			}
		}

		this->tabla.agregar_entrada(this->pos_lexico, this->pos_punteros,cant_doc);
		this->comprimir_termino(termino_actual, longitud, termino_anterior, longitud_anterior);

		this->comprimir_punteros(cant_doc, par);
		i = 0;
		while (i < cant_doc) {
			delete par[i];
			i++;
		}
		memset(termino_anterior, 0, LONG_TERMINO_MAX);
		memcpy(termino_anterior, termino_actual, LONG_TERMINO_MAX);
		longitud_anterior = longitud;

		CANTIDAD++;
	}

	std::cout << "LA Cantidad de terminos es : " << CANTIDAD;
	tabla_indice* tablita = this->tabla.get_tabla();

	FILE* tabla_f = fopen(this->path_tabla.c_str(), "w+");
	int size_tabla = tabla.get_size();
	fwrite(tablita, size_tabla, sizeof(char), tabla_f);
	fclose(tabla_f);

	fwrite(this->buffer_lexico, this->pos_lexico_offset, sizeof(char),lexico);

	this->compresorPunteros.grabarBufferActual();
	this->compresorPunteros.cerrar();
	fclose(this->lexico);
	fclose(input);
	remove (path_entrada.c_str());
	delete[] buffer;
}


void CompresorDeTerminos::comprimir_termino(char* termino, int longitud, char* termino_anterior,
		int longitud_anterior) {
	unsigned short int distintos, iguales;
	distintos = iguales = 0;
	this->frontcoding.comprimir_termino(termino, longitud, &iguales, &distintos, termino_anterior, longitud_anterior);
	if (iguales == 0) {
		if ((this->pos_lexico_offset + longitud) > LEXICO_SIZE) {
			fwrite(this->buffer_lexico, this->pos_lexico_offset, sizeof(char), lexico);
			memset(buffer_lexico,0,LEXICO_SIZE);
			this->pos_lexico_offset = 0;
		}
		memcpy(&this->buffer_lexico[pos_lexico_offset], termino, longitud);
		this->pos_lexico = this->pos_lexico + longitud;
		this->pos_lexico_offset = this->pos_lexico_offset + longitud;
	}
	else {
		if ((this->pos_lexico_offset + distintos) > LEXICO_SIZE) {
			fwrite(this->buffer_lexico, this->pos_lexico_offset, sizeof(char), lexico);
			memset(buffer_lexico,0,LEXICO_SIZE);
			this->pos_lexico_offset = 0;
		}
		memcpy(&this->buffer_lexico[pos_lexico_offset], (termino+iguales), distintos );
		this->pos_lexico = this->pos_lexico + distintos;
		this->pos_lexico_offset = this->pos_lexico_offset + distintos;
	}
	this->tabla.set_datos_frontcoding((longitud-iguales), iguales);
}

void CompresorDeTerminos::comprimir_punteros(int nro_doc, Doc_frec* par[]) {
	this->compresorPunteros.comprimir(par, nro_doc);
	this->pos_punteros = this->compresorPunteros.getPosActual();
}


void CompresorDeTerminos::descomprimir() {


}
